<?php
// +----------------------------------------------------------------------
// | zlserver [ 小程序 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2018 http://www.zhongliansoft.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: tony <tanyu@zhongliansoft.com>
// +----------------------------------------------------------------------
namespace app\job\import;

use think\exception\ErrorException;
use think\facade\Validate;
use think\queue\Job;
use app\common\model\DeviceCat as DeviceCatModel;
use app\common\model\Brand as BrandModel;
use app\common\model\DeviceType as DeviceTypeModel;
use app\common\model\Device as DeviceModel; 

use app\common\model\Ietask;
use think\facade\Log;

class Device
{
    protected $rule = [
        'name' => 'require|max:40',
        // 'cat_id' => 'require|in:声波设备,蓝牙设备', 
        // 'brand_id' => 'require|in:紫宇,凯路创新', 
        // 'type_id' => 'require|in:吹风机,直饮水,洗浴', 
        'sub_id' => 'require',
        'area_id' => 'require',
        'status' => 'require|in:启用,停用'
    ];
    protected $msg = [
        'name.require' => '设备名称必填',
        'name.max' => '账号最长40个字符',
        // 'cat_id.require' => '类型名称必填',
        // 'cat_id.in' => '请选择合法的类型名称',
        // 'brand_id.require' => '品牌名称必填',
        // 'brand_id.in' => '请选择合法的品牌名称',
        // 'type_id.require' => '使用场景必填',
        // 'type_id.in' => '请选择合法的类型名称',
        'sub_id.require' => '出厂编号必填', 
        'area_id.require' => '设备位置必填', 
        'status.in' => '请填写合法的状态 启用 或 停用',
        'status.require' => '状态必填'
    ];

    // 数据校验
    public function check($fileId, $filePath)
    {
        $re = [
            'count' => 0,
            'code' => 0,
            'msg' => ''
        ];

        $deviceModel = new DeviceModel();

        $deviceCatModel = new DeviceCatModel();
        $brandModel = new BrandModel();
        $deviceTypeModel = new DeviceTypeModel();

        $data = [];
        $errorData = [];
        try {
            $resXls=import_excel($filePath);  

            if ($resXls['status']) {
                // 清理导入提示
                unset($resXls['data'][0]);
                // 取表头
                $header = $resXls['data'][1];
                unset($resXls['data'][1]);
                $title = $deviceModel->csvHeader();
                $fields = [];

                // 遍历表头
                $last_index = 0;
                foreach ($title as $key => $val) {
                    // 从导入的数据表中查找字段位置
                    $index = array_search($val['desc'], $header);
                    if ($index !== false) {
                        $fields[] = [
                            'index' => $index,
                            'value' => $val['id']
                        ];
                    }
                    $last_index = $index;
                }
 
                if(count($fields) != 7) { 
                    $re['msg']  = '文件格式错误！请先下载导入模板，按模板要求准备导入数据后再次导入！';
                    $re['code']  = -1;
                    return $re;
                } else {

                    $brandList = $brandModel->getBrandList();
                    $deviceCatList = $deviceCatModel->getDeviceCatList();
                    $deviceTypeList = $deviceTypeModel->getDeviceTypeList();

                    // 数据填充
                    $iData = [];
                    if ($fields) {
                        $i = 0;
                        foreach ($resXls['data'] as $key => $val) {
                            foreach ($fields as $fkey => $fval) {
                                $iData[$i][$fval['value']] = $val[$fval['index']];
                                if(is_object($iData[$i][$fval['value']])) {
                                    $iData[$i][$fval['value']] = $iData[$i][$fval['value']]->__toString();
                                }
                            }
                            $i++;
                        }
                    }
    
                    // 增加描述字段
                    $fields[] = [
                        'index' => $last_index + 1,
                        'value' => 'desc'
                    ];

                    $count = count($iData);
                    $errCount = 0;
    
                    $deviceList = $deviceModel->getDeviceList(); 
                    $tmp_arr = array(); 
                     
                    // 数据预处理 
                    foreach ($iData as $key => $val) {
                        $errFind = false;
                        //校验数据
                        $validate = new \think\Validate($this->rule, $this->msg);
                        $validate->batch(true);

                        // 数据预处理
                        $time = time();
                        $device['name'] = trim($val['name']) == null ? '' : $val['name'];
                        $device['cat_id'] = trim($val['cat_id']);
                        $device['brand_id'] = trim($val['brand_id']);
                        $device['type_id'] = trim($val['type_id']);
                        $device['sub_id'] = trim($val['sub_id']);
                        $device['area_id'] = trim($val['area_id']);
                        $device['status'] = trim($val['status']);
                        $device['desc'] = '';
                        $device['error'] = 0;
    
                        // 数据库检测
                        if (!$validate->check($device)) {
                            $device['error'] = 1;
                            $errCount = $errCount + 1;
                            $errFind = true;
    
                            $index = 0;
                            foreach ($validate->getError() as $errKey => $value) {
                                if($index == 0) {
                                    $device['desc']  = $device['desc'] . $value;
                                } else {
                                    $device['desc']  = $device['desc'] . ';' . $value;
                                }
                                $index++;
                            }
                        }
 
                        if (!array_key_exists($device['cat_id'], $deviceCatList)) { 
                            // 数据库检测
                            $device['error'] = 1;
                            if($errFind) { 
                                if($device['cat_id'] == ''){
                                    $device['desc']  = $device['desc'] . ';' . '类型名称必填'; 
                                } else {
                                    $device['desc']  = $device['desc'] . ';' . '类型名称错误:请参考模板类型名称介绍，或咨询系统管理员'; 
                                }
                            } else {
                                $errCount = $errCount + 1;
                                $errFind = true;
                                if($device['cat_id'] == ''){
                                    $device['desc'] =  '类型名称必填';
                                } else {
                                    $device['desc'] =  '类型名称错误:请参考模板类型名称介绍，或咨询系统管理员';
                                }
                            }
                        }

                        if (!array_key_exists($device['brand_id'], $brandList)) { 
                            // 数据库检测
                            $device['error'] = 1;
                            if($errFind) { 
                                if($device['brand_id'] == ''){
                                    $device['desc']  = $device['desc'] . ';' . '品牌名称必填'; 
                                } else {
                                    $device['desc']  = $device['desc'] . ';' . '品牌名称错误:请参考模板品牌名称介绍，或咨询系统管理员'; 
                                }
                            } else {
                                $errCount = $errCount + 1;
                                $errFind = true;
                                if($device['cat_id'] == ''){
                                    $device['desc'] =  '品牌名称必填';
                                } else {
                                    $device['desc'] =  '品牌名称错误:请参考模板品牌名称介绍，或咨询系统管理员';
                                }
                            }
                        }

                        if (!array_key_exists($device['type_id'], $deviceTypeList)) { 
                            // 数据库检测
                            $device['error'] = 1;
                            if($errFind) { 
                                if($device['type_id'] == ''){
                                    $device['desc']  = $device['desc'] . ';' . '使用场景必填'; 
                                } else {
                                    $device['desc']  = $device['desc'] . ';' . '使用场景错误:请参考模板使用场景介绍，或咨询系统管理员'; 
                                }
                            } else {
                                $errCount = $errCount + 1;
                                $errFind = true;
                                if($device['cat_id'] == ''){
                                    $device['desc'] =  '使用场景必填';
                                } else {
                                    $device['desc'] =  '使用场景错误:请参考模板使用场景介绍，或咨询系统管理员';
                                }
                            }
                        }
 
                        // 区域检测
                        $areaArray = preg_split("/[\s;]+/", $device['area_id']);
                        if (strpos($device['area_id'], '；') !== false || strpos($device['area_id'], '、') !== false || strpos($device['area_id'], '，') !== false) {
                            $device['error'] = 1;
                            
                            if($errFind) {
                                $device['desc'] =  $device['desc'] . ';' . '区域层级分割符号错误，请使用英文[;]';
                            } else {
                                $errCount = $errCount + 1;
                                $errFind = true;
                                $device['desc'] =  '区域层级分割符号错误，请使用英文[;]';
                            }
                        }  else if($device['area_id'] != '' && count($areaArray) !=3 ) {
                            $device['error'] = 1;
                            if($errFind) {
                                $device['desc'] = $device['desc'] . ';' . '区域层级应为3级，请参考导入模板区域格式要求！'; 
                            } else {
                                $errCount = $errCount + 1;
                                $errFind = true;
                                $device['desc'] = $device['desc'] . '区域层级应为3级，请参考导入模板区域格式要求！'; 
                            }
                        }

                        // 生成关键字
                        $deviceKey = $device['cat_id'].'-'.$device['brand_id'].'-'.$device['type_id'].'-'.$device['sub_id'];
 
                        if($deviceKey != '---') {
                            // 判断账号是否重复
                            if (in_array($deviceKey, $deviceList)) {
                                $device['error'] = 1;

                                if($errFind) {
                                    $device['desc'] =  $device['desc'] . ';' . $deviceKey . '已存在';
                                } else {
                                    $errCount = $errCount + 1;
                                    $errFind = true;
                                    $device['desc'] =  $deviceKey . '已存在';
                                }
                            }
    
                            // 自身检测
                            if (in_array($deviceKey, $tmp_arr)) { //搜索$v[$key]是否在$tmp_arr数组中存在，若存在返回true
                                $device['error'] = 1;
                                if($errFind) {
                                    $device['desc'] = $device['desc'] . ';' . '导入数据中存在重复数据：'.$deviceKey; 
                                } else {
                                    $errCount = $errCount + 1;
                                    $errFind = true;
                                    $device['desc'] = $device['desc'] . '导入数据中存在重复数据：'.$deviceKey; 
                                }
                            } else {
                                $tmp_arr[] = $deviceKey;
                            }
                        }

                        if ($device['error'] == 1) {
                            $errorData[$errCount - 1] = $device;
                        }
    
                        $data[$key] = $device;
                        unset($device);
                    }
                } 
            } else {
                $re['msg']  = $resCsv['msg'];
                $re['code']  = -1;
                return $re;
            }
        } catch (Exception $e) {
            $re['msg']  = $e->getMessage();
            $re['code']  = -1;
            return $re;
        }

        $re['count'] = $count;
        $re['errCount'] = $errCount;
        $re['data'] = json_encode($data);
        $re['fileId'] = $fileId;
        $re['filePath'] = $filePath;
        $re['errData'] = json_encode($errorData);
        return $re;
    }

    //执行导入任务
    public function exec(Job $job, $params)
    {
        $ietaskModle = new Ietask();
        $deviceCatModel = new DeviceCatModel();
        $brandModel = new BrandModel();
        $deviceTypeModel = new DeviceTypeModel();
        $deviceModel = new DeviceModel(); 
        $message = [];
        $count = 0;         // 记录总数
        $progress = 0;
        try {
            $file = json_decode($params['params'], true);
 
            $resXls=import_excel($file['file_path']); 
            $count = count($resXls['data'])-2;

            if ($resXls['status']) {
                // 清理导入提示
                unset($resXls['data'][0]);
                // 取表头
                $header = $resXls['data'][1];
                unset($resXls['data'][1]);
                $title = $deviceModel->csvHeader();
                $fields = [];

                foreach ($title as $key => $val) {
                    $index = array_search($val['desc'], $header);
                    if ($index >= 0) {
                        $fields[] = [
                            'index' => $index,
                            'value' => $val['id']
                        ];
                    }
                }
                $iData = [];
                if ($fields) {
                    $i = 0;
                    foreach ($resXls['data'] as $key => $val) {
                        foreach ($fields as $fkey => $fval) {
                            $iData[$i][$fval['value']] = $val[$fval['index']];
                            if(is_object($iData[$i][$fval['value']])) {
                                $iData[$i][$fval['value']] = $iData[$i][$fval['value']]->__toString();
                            }
                        }
                        $i++;
                    }
                }

                $brandList = $brandModel->getBrandList();
                $deviceCatList = $deviceCatModel->getDeviceCatList();
                $deviceTypeList = $deviceTypeModel->getDeviceTypeList();

                unset($device_comment);
                $device_comment = [];
 
                $area_array = [];       // 用于插入地区信息
                foreach ($iData as $key => $val) {
                    $status = trim($val['status']) == '启用' ? $deviceModel::DEVICE_STATUS_YES : $deviceModel::DEVICE_STATUS_NO;
                    
                    $area_id = 0;
                    if(!array_key_exists(trim($val['area_id']), $area_array)) {
                        $area_id = set_area(trim($val['area_id']));
                        $area_array[trim($val['area_id'])] = $area_id;
                    } else {
                        $area_id = $area_array[trim($val['area_id'])];
                    }

                    $device_comment[] = [
                        'name'    => trim($val['name']),
                        'cat_id'  => $deviceCatList[trim($val['cat_id'])],
                        'brand_id' => $brandList[trim($val['brand_id'])],
                        'type_id' => $deviceTypeList[trim($val['type_id'])],
                        'sub_id'    => trim($val['sub_id']),
                        'area_id'  => $area_id,
                        'status'    => $status,
                        'ctime' => time(),
                        'utime' => time()
                    ];
     
                    // 每隔100条数据更新一次数据处理进度
                    $progress++; 
                    if($progress %100==0) {
                        // 批量插入数据
                        $deviceModel->startTrans(); 
                        $num = $deviceModel->insertAll($device_comment);
                        if($num != 100) {
                            $deviceModel->rollback();
                            // 生成关键字
                            $deviceKey = $device_comment['cat_id'].'-'.$device_comment['brand_id'].'-'.$device_comment['type_id'].'-'.$device_comment['sub_id'];
                            Log::record($deviceKey . '设备数据保存失败');
                        } else {                        
                            $deviceModel->commit();
                        }

                        // 清理环境
                        unset($device_comment);
                        $device_comment = [];
                    }
                }

                // 批量插入数据
                $deviceModel->startTrans(); 
                $num = $deviceModel->insertAll($device_comment);               
                $deviceModel->commit(); 
 
                $uData['status'] = $ietaskModle::IMPORT_SUCCESS_STATUS;
                $uData['message'] = '导入成功';
                if ($message) {
                    $uData['message'] .= json_encode($message);
                }

                $uData['count'] = $count;
                $ietaskModle->update($uData, ['id' => $params['task_id']]);
            } else {
                $uData['status'] = $ietaskModle::IMPORT_FAIL_STATUS;
                $uData['message'] = $resCsv['msg'];
                $uData['utime'] = time();
                $ietaskModle->update($uData, ['id' => $params['task_id']]);
            }
        } catch (Exception $e) {
            $message[] = $e->getMessage();
        }
        if ($job->attempts() > 3) {
            $uData['status'] = $ietaskModle::IMPORT_FAIL_STATUS;
            $uData['message'] = '导入执行失败';
            $uData['utime'] = time();
            $ietaskModle->update($uData, ['id' => $params['task_id']]);
            $job->delete();
        }
    }

    public function failed($data)
    {

        // ...任务达到最大重试次数后，失败了
    }
}
